package com.zhihu_lvliangi_android.service;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.json.JSONArray;
import org.json.JSONObject;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.Fragment;
import android.text.TextUtils;
import android.util.Log;

import com.android.log.LogUtil;
import com.android.task.Task;
import com.android.task.TaskCallBack;
import com.android.task.TaskOperate;
import com.android.volley.AuthFailureError;
import com.android.volley.DefaultRetryPolicy;
import com.android.volley.NetworkResponse;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.RetryPolicy;
import com.android.volley.VolleyError;
import com.android.volley.VolleyLog;
import com.android.volley.toolbox.JsonArrayRequest;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import com.android.widget.dialog.loading.LoadingDialog;
import com.zhihu_lvliangi_android.option.parent.ParentFragment;
import com.zhihu_lvliangi_android.service.volley.StringRequestPost;
import com.zhihu_lvliangi_android.service.volley.StringRequestPut;
import com.zhihu_lvliangi_android.service.volley.VolleyForHttps;

public class ClientTask implements Response.ErrorListener, TaskOperate {

	public static int SOCKET_TIMEOUT = 10000;
	private RequestQueue mRequestQueue, mRequestQueueForHttps;
	private Context context;
	public static final String COOKIES = "Cookies";

	private static final String KEY_CLASSNAME = "ClassName";
	private static final String KEY_TASKID = "TaskId";
	/**
	 * handler类型
	 */
	private static final int Notify_DATA = 0;
	private static final int Notify_VIEW_SHOW = 1;
	private static final int Notify_VIEW_CANCEL = 2;

	private ParentFragment fragment;

	public enum LoadingType {
		CUSTUM_PUBLIC, CUSTUM_PRIVATE
	}

	public ResponseErrorListener responseErrorListener;

	public interface ResponseErrorListener {

		public void onErrorResponse(VolleyError error);

	}

	private LoadingType loadingType = LoadingType.CUSTUM_PUBLIC;
	private LoadingDialog loadingDialog;

	public ClientTask(Context context) {
		super();
		this.context = context;
	}

	/**
	 * get请求网络的方法
	 * 
	 * @param dataFormat
	 * @param url
	 * @param listener
	 */
	@SuppressLint("NewApi")
	@SuppressWarnings("unchecked")
	public Request<?> executeGet(Enum<?> reqId, DataFormat dataFormat, String url, Response.Listener<?> listener) {
		showLoadingView(getActivity(listener));
		Request<?> request = null;
		switch (dataFormat) {
		case STRING:
			request = new StringRequest(url, (Response.Listener<String>) listener, this) {

				@Override
				protected Response<String> parseNetworkResponse(NetworkResponse response) {
					Response<String> superResponse = super.parseNetworkResponse(response);
					Map<String, String> responseHeaders = response.headers;
					String rawCookies = responseHeaders.get("Set-Cookie");
					String cookies = MobileApplication.preferences.getString(ClientTask.COOKIES, null);
					if (cookies == null) {
						MobileApplication.preferences.edit().putString(ClientTask.COOKIES, rawCookies).commit();
					}
					return superResponse;
				}

				@Override
				public Map<String, String> getHeaders() throws AuthFailureError {
					String cookies = MobileApplication.preferences.getString(ClientTask.COOKIES, null);
					if (cookies != null && !cookies.isEmpty()) {
						HashMap<String, String> headers = new HashMap<String, String>();
						headers.put("Cookie", cookies);
						return headers;
					}
					return super.getHeaders();
				}
			};
			break;
		case JSONARRAY:
			request = new JsonArrayRequest(url, (Response.Listener<JSONArray>) listener, this) {

				@Override
				protected Response<JSONArray> parseNetworkResponse(NetworkResponse response) {
					Response<JSONArray> superResponse = super.parseNetworkResponse(response);
					Map<String, String> responseHeaders = response.headers;
					String rawCookies = responseHeaders.get("Set-Cookie");
					String cookies = MobileApplication.preferences.getString(ClientTask.COOKIES, null);
					if (cookies == null) {
						MobileApplication.preferences.edit().putString(ClientTask.COOKIES, rawCookies).commit();
					}
					return superResponse;
				}

				@Override
				public Map<String, String> getHeaders() throws AuthFailureError {
					String cookies = MobileApplication.preferences.getString(ClientTask.COOKIES, null);
					if (cookies != null && !cookies.isEmpty()) {
						HashMap<String, String> headers = new HashMap<String, String>();
						headers.put("Cookie", cookies);
						return headers;
					}
					return super.getHeaders();
				}

			};
			break;
		case JSONOBJECT:
			request = new JsonObjectRequest(url, null, (Response.Listener<JSONObject>) listener, this) {

				@Override
				protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
					Response<JSONObject> superResponse = super.parseNetworkResponse(response);
					Map<String, String> responseHeaders = response.headers;
					String rawCookies = responseHeaders.get("Set-Cookie");
					String cookies = MobileApplication.preferences.getString(ClientTask.COOKIES, null);
					if (cookies == null) {
						MobileApplication.preferences.edit().putString(ClientTask.COOKIES, rawCookies).commit();
					}
					return superResponse;
				}

				@Override
				public Map<String, String> getHeaders() throws AuthFailureError {
					String cookies = MobileApplication.preferences.getString(ClientTask.COOKIES, null);
					if (cookies != null && !cookies.isEmpty()) {
						HashMap<String, String> headers = new HashMap<String, String>();
						headers.put("Cookie", cookies);
						return headers;
					}
					return super.getHeaders();
				}

			};
			break;
		default:
			break;
		}
		if (request != null) {
			RetryPolicy retryPolicy = new DefaultRetryPolicy(SOCKET_TIMEOUT, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
			request.setRetryPolicy(retryPolicy);
			request.setReqId(reqId);
			request = addToRequestQueue(request);
		}
		return request;
	}

	/**
	 * post请求网络方法,一般情况下只会返回String类型的数据
	 * 
	 * @param dataFormat
	 * @param url
	 * @param listener
	 */
	@SuppressWarnings("unchecked")
	public void executePost(Enum<?> reqId, DataFormat dataFormat, String url, final Map<String, String> paramsMap, Response.Listener<?> listener) {
		showLoadingView(getActivity(listener));
		Request<?> request = null;
		switch (dataFormat) {
		case STRING:
			request = new StringRequestPost(url, paramsMap, (Response.Listener<String>) listener, this);
			break;
		case JSONARRAY:
			Log.w(MobileApplication.TAG, "JSONARRAY 现在只支持 HTTP GET");
			break;
		case JSONOBJECT:
			request = new JsonObjectRequest(url, new JSONObject(paramsMap), (Response.Listener<JSONObject>) listener, this) {

				@Override
				protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
					Response<JSONObject> superResponse = super.parseNetworkResponse(response);
					Map<String, String> responseHeaders = response.headers;
					String rawCookies = responseHeaders.get("Set-Cookie");
					String cookies = MobileApplication.preferences.getString(ClientTask.COOKIES, null);
					if (cookies == null) {
						MobileApplication.preferences.edit().putString(ClientTask.COOKIES, rawCookies).commit();
					}
					return superResponse;
				}

				@Override
				public Map<String, String> getHeaders() throws AuthFailureError {
					String cookies = MobileApplication.preferences.getString(ClientTask.COOKIES, null);
					if (cookies != null && cookies.length() > 0) {
						HashMap<String, String> headers = new HashMap<String, String>();
						headers.put("Cookie", cookies);
						return headers;
					}
					return super.getHeaders();
				}

			};
			break;
		default:
			break;
		}
		if (request != null) {
			RetryPolicy retryPolicy = new DefaultRetryPolicy(SOCKET_TIMEOUT, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
			request.setRetryPolicy(retryPolicy);
			request.setReqId(reqId);
			addToRequestQueue(request);
		}
	}

	@SuppressWarnings("unchecked")
	public void executePost(Enum<?> reqId, DataFormat dataFormat, String url, final JSONObject paramsJSONObject, Response.Listener<?> listener) {
		showLoadingView(getActivity(listener));
		Request<?> request = null;
		switch (dataFormat) {
		case STRING:
			Log.w(MobileApplication.TAG, "JSONARRAY 现在只支持 HTTP GET");
			break;
		case JSONARRAY:
			Log.w(MobileApplication.TAG, "JSONARRAY 现在只支持 HTTP GET");
			break;
		case JSONOBJECT:
			request = new JsonObjectRequest(url, paramsJSONObject, (Response.Listener<JSONObject>) listener, this) {

				@Override
				protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
					Response<JSONObject> superResponse = super.parseNetworkResponse(response);
					Map<String, String> responseHeaders = response.headers;
					String rawCookies = responseHeaders.get("Set-Cookie");
					String cookies = MobileApplication.preferences.getString(ClientTask.COOKIES, null);
					if (cookies == null) {
						MobileApplication.preferences.edit().putString(ClientTask.COOKIES, rawCookies).commit();
					}
					return superResponse;
				}

				@SuppressLint("NewApi")
				@Override
				public Map<String, String> getHeaders() throws AuthFailureError {
					String cookies = MobileApplication.preferences.getString(ClientTask.COOKIES, null);
					if (cookies != null && !cookies.isEmpty()) {
						HashMap<String, String> headers = new HashMap<String, String>();
						headers.put("Cookie", cookies);
						return headers;
					}
					return super.getHeaders();
				}

			};
			break;
		default:
			break;
		}
		if (request != null) {
			RetryPolicy retryPolicy = new DefaultRetryPolicy(SOCKET_TIMEOUT, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
			request.setRetryPolicy(retryPolicy);
			request.setReqId(reqId);
			addToRequestQueue(request);
		}
	}

	/**
	 * post请求网络方法,一般情况下只会返回String类型的数据
	 * 
	 * @param dataFormat
	 * @param url
	 * @param listener
	 */
	@SuppressWarnings("unchecked")
	public void executePostForHttps(Enum<?> reqId, DataFormat dataFormat, String url, final Map<String, String> paramsMap, Response.Listener<?> listener) {
		showLoadingView(getActivity(listener));
		Request<?> request = null;
		switch (dataFormat) {
		case STRING:
			request = new StringRequestPost(url, paramsMap, (Response.Listener<String>) listener, this);
			break;
		case JSONARRAY:
			Log.w(MobileApplication.TAG, "JSONARRAY 现在只支持 HTTP GET");
			break;
		case JSONOBJECT:
			request = new JsonObjectRequest(url, new JSONObject(paramsMap), (Response.Listener<JSONObject>) listener, this);
			break;
		default:
			break;
		}
		if (request != null) {
			RetryPolicy retryPolicy = new DefaultRetryPolicy(SOCKET_TIMEOUT, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
			request.setRetryPolicy(retryPolicy);
			request.setReqId(reqId);
			addToRequestQueueForHttps(request);
		}
	}

	// -- 实现Response.ErrorListener接口中的方法
	@Override
	public void onErrorResponse(VolleyError error) {
		cancelLoadingView();
		if (fragment != null) {
			fragment.recoveryView();
		}
		VolleyLog.e("Error: ", error.getMessage());
		if (error.networkResponse == null) {
			return;
		}
		if (responseErrorListener != null) {
			responseErrorListener.onErrorResponse(error);
		}
	}

	/**
	 * put请求网络方法,一般情况下只会返回String类型的数据
	 * 
	 * @param dataFormat
	 * @param url
	 * @param listener
	 */
	@SuppressWarnings("unchecked")
	public void executePut(Enum<?> reqId, DataFormat dataFormat, String url, final Map<String, String> paramsMap, Response.Listener<?> listener) {
		showLoadingView(getActivity(listener));
		Request<?> request = null;
		switch (dataFormat) {
		case STRING:
			request = new StringRequestPut(url, paramsMap, (Response.Listener<String>) listener, this);
			break;
		case JSONARRAY:
			Log.w(MobileApplication.TAG, "JSONARRAY 现在只支持 HTTP GET");
			break;
		case JSONOBJECT:
			Log.w(MobileApplication.TAG, "JSONOBJECT 现在只支持 HTTP GET POST");
			break;
		default:
			break;
		}
		if (request != null) {
			RetryPolicy retryPolicy = new DefaultRetryPolicy(SOCKET_TIMEOUT, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
			request.setRetryPolicy(retryPolicy);
			request.setReqId(reqId);
			addToRequestQueue(request);
		}
	}

	/**
	 * delete请求网络方法,一般情况下只会返回String类型的数据
	 * 
	 * @param dataFormat
	 * @param url
	 * @param listener
	 */
	@SuppressWarnings("unchecked")
	public void executeDelete(Enum<?> reqId, DataFormat dataFormat, String url, Response.Listener<?> listener) {
		showLoadingView(getActivity(listener));
		Request<?> request = null;
		switch (dataFormat) {
		case STRING:
			request = new StringRequest(Request.Method.DELETE, url, (Response.Listener<String>) listener, this) {

				@Override
				public Map<String, String> getHeaders() throws AuthFailureError {
					String cookies = MobileApplication.preferences.getString(ClientTask.COOKIES, null);
					if (cookies != null && cookies.length() > 0) {
						HashMap<String, String> headers = new HashMap<String, String>();
						headers.put("Cookie", cookies);
						return headers;
					}
					return super.getHeaders();
				}
			};
			break;
		case JSONARRAY:
			Log.w(MobileApplication.TAG, "JSONARRAY 现在只支持 HTTP GET");
			break;
		case JSONOBJECT:
			Log.w(MobileApplication.TAG, "JSONOBJECT 现在只支持 HTTP GET POST");
			break;
		default:
			break;
		}
		if (request != null) {
			RetryPolicy retryPolicy = new DefaultRetryPolicy(SOCKET_TIMEOUT, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
			request.setRetryPolicy(retryPolicy);
			request.setReqId(reqId);
			addToRequestQueue(request);
		}
	}

	/**
	 * 获取请求队列
	 * 
	 * @return
	 */
	public RequestQueue getRequestQueue() {
		if (mRequestQueue == null) {
			mRequestQueue = Volley.newRequestQueue(context);
		}
		return mRequestQueue;
	}

	/**
	 * 获取请求队列
	 * 
	 * @return
	 */
	public RequestQueue getRequestQueueForHttps() {
		if (mRequestQueueForHttps == null) {
			mRequestQueueForHttps = VolleyForHttps.newRequestQueue(context);
		}
		return mRequestQueueForHttps;
	}

	/**
	 * 将请求添加到请求队列
	 * 
	 * @param req
	 * @param tag
	 */
	public <T> Request<T> addToRequestQueue(Request<T> req, String tag) {
		req.setTag(TextUtils.isEmpty(tag) ? MobileApplication.TAG : tag);
		VolleyLog.d("Adding request to queue: %s", req.getUrl());
		return getRequestQueue().add(req);
	}

	/**
	 * 将请求添加到请求队列
	 * 
	 * @param req
	 * @param tag
	 */
	public <T> void addToRequestQueueForHttps(Request<T> req, String tag) {
		req.setTag(TextUtils.isEmpty(tag) ? MobileApplication.TAG : tag);
		VolleyLog.d("Adding request to queue: %s", req.getUrl());
		getRequestQueueForHttps().add(req);
	}

	/**
	 * 将请求添加到请求队列
	 * 
	 * @param req
	 */
	public <T> Request<T> addToRequestQueue(Request<T> req) {
		return addToRequestQueue(req, MobileApplication.TAG);
	}

	/**
	 * 将请求添加到请求队列
	 * 
	 * @param req
	 */
	public <T> void addToRequestQueueForHttps(Request<T> req) {
		addToRequestQueueForHttps(req, MobileApplication.TAG);
	}

	/**
	 * 中断正在执行的请求
	 * 
	 * @param tag
	 */
	public void cancelPendingRequests(Object tag) {
		if (mRequestQueue != null) {
			mRequestQueue.cancelAll(tag == null ? MobileApplication.TAG : tag);
		}
	}

	/**
	 * 中断正在执行的请求
	 * 
	 * @param tag
	 */
	public void cancelPendingRequestsForHttps(Object tag) {
		if (mRequestQueueForHttps != null) {
			mRequestQueueForHttps.cancelAll(tag == null ? MobileApplication.TAG : tag);
		}
	}

	public Handler handler = new Handler(new Handler.Callback() {

		@Override
		public boolean handleMessage(Message msg) {
			switch (msg.arg1) {
			case Notify_VIEW_SHOW:
				if (!loadingDialog.isShowing()) {
					loadingDialog.show();
				}
				break;
			case Notify_VIEW_CANCEL:
				if (loadingDialog.isShowing()) {
					loadingDialog.cancel();
				}
				break;
			case Notify_DATA:
				Bundle bundle = msg.getData();
				String className = msg.getData().getString(KEY_CLASSNAME);
				TaskCallBack taskCallBack = MobileApplication.taskCallBacks.get(className);
				if (taskCallBack != null) {
					taskCallBack.refresh((TaskID) bundle.getSerializable(KEY_TASKID), msg.obj);
				} else {
					LogUtil.w("MobileApplication.taskCallBacks中没有实现TaskCallBack接口的类");
				}
				break;
			default:
				break;
			}
			return true;
		}
	});

	public Activity getActivity(Response.Listener<?> listener) {
		Activity ac = null;
		if (listener instanceof Activity) {
			ac = (Activity) listener;
		} else if (listener instanceof ParentFragment) {
			fragment = (ParentFragment) listener;
			ac = fragment.getActivity();
		}
		return ac;
	}

	public void showLoadingView(Activity activity) {
		if (fragment != null) {
			if (fragment.isUseProgressFragment()) {
				return;
			}
		}
		switch (loadingType) {
		case CUSTUM_PUBLIC:
			if (activity == null) {
				Log.e(MobileApplication.TAG, "Activity为空，LoadingDialog无法初始化...");
				return;
			}
			if (loadingDialog == null || loadingDialog.context != activity) {
				loadingDialog = new LoadingDialog(activity);
			}
			Message message = handler.obtainMessage();
			message.arg1 = Notify_VIEW_SHOW;
			handler.sendMessage(message);
			break;
		case CUSTUM_PRIVATE:
			loadingType = LoadingType.CUSTUM_PUBLIC;
			break;
		default:
			break;
		}
	}

	public void cancelLoadingView() {
		if (loadingDialog != null) {
			Message message = handler.obtainMessage();
			message.arg1 = Notify_VIEW_CANCEL;
			handler.sendMessage(message);
		}
	}

	@Override
	public void operate(Task task) {
		Message message = handler.obtainMessage();
		message.arg1 = Notify_DATA;
		Bundle bundle = new Bundle();
		bundle.putString(KEY_CLASSNAME, task.getClassName());
		bundle.putSerializable(KEY_TASKID, task.getTaskIdEnum());
		message.setData(bundle);
		switch ((TaskID) task.getTaskIdEnum()) {
		// case TASK_FINDPLUGINS:
		// PluginOperate.findPlugins(task, message);
		// break;
		default:
			break;
		}
		handler.sendMessage(message);
	}

	@Override
	public void show() {
		ComponentName componentName = MobileApplication.activityManager.getRunningTasks(1).get(0).topActivity;
		Activity activity = getTaskCallBackByName(componentName);
		showLoadingView(activity);
	}

	@Override
	public void cancel() {
		cancelLoadingView();
	}

	@SuppressLint("NewApi")
	public Activity getTaskCallBackByName(ComponentName name) {
		Activity ac = null;
		Set<Entry<String, TaskCallBack>> entries = MobileApplication.taskCallBacks.entrySet();
		for (Entry<String, TaskCallBack> entry : entries) {
			if (entry.getValue().getClass().getName().startsWith(name.getClassName())) {
				TaskCallBack taskCallBack = entry.getValue();
				if (taskCallBack instanceof Activity) {
					ac = (Activity) taskCallBack;
				} else if (taskCallBack instanceof Fragment) {
					ac = ((Fragment) taskCallBack).getActivity();
				}
				break;
			}
		}
		return ac;
	}

	public void setLoadingType(LoadingType loadingType) {
		this.loadingType = loadingType;
	}

}
